package net.animats.music;

import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class Key {

    enum Position {

        UNKNOWN, TONIC, SUPERTONIC, MEDIANT, SUBDOMINANT, DOMINANT, SUBMEDIANT, LEADINGTONE
    }

    public static final int UNKNOWN = 0;
    public static final int TONIC = 1;
    public static final int SUPERTONIC = 2;
    public static final int MEDIANT = 3;
    public static final int SUBDOMINANT = 4;
    public static final int DOMINANT = 5;
    public static final int SUBMEDIANT = 6;
    public static final int LEADINGTONE = 7;

    private static Map<String, Key> keys = new HashMap<String, Key>();
    private Scale scale;
    private List<Chord> chords = new ArrayList<Chord>();

    static {
        for (int index = 0; index < 12; index++) {
            // LOOP THROUGH AN OCTAVE OF ROOT NOTES AND CALCULATE ALL
            // THE CHORDS THAT BELONG IN THE MAJOR SCALE OF THAT NOTE
            Note rootNote = Note.getNote(index);
            ;
            Scale scale = new Scale(rootNote, ScaleType.getScaleType("Major"));
            keys.put(scale.getName(), new Key(scale));
        }
        //System.out.println("Created: ");
        //for (String it : keys.keySet()) {
        //	System.out.println(it + " ");
        //}
    }

    public boolean inThisKey(Song _song) {
        //System.out.println("Testing key: " + getName());
        for (Chord chord : _song.getChords()) {
            if (!chords.contains(chord)) {
                // THERE IS A CHORD IN THE SONG THAT IS NOT IN THIS KEY
                //System.out.println(getName() + " doesn't contain a " + chord.getName());
                return false;
            }
        }

        // NONE OF THE CHORDS IN THE SONG PASSED WEREN'T IN THIS KEY
        return true;
    }

    private Key(Scale _scale) {
        scale = _scale;

        int position = 1;

        for (Note note : _scale.getNotes()) {
            // LOOP THROUGH ALL THE NOTES IN THE GIVEN SCALE
            // AND CREATE THE CHORDS. THIS IS CHEATING AT THE
            // MOMENT IN THAT THE CHORD TYPES ARE HARD CODED
            // FOR A MAJOR SCALE
            // KIELBASA SHOULD ULTIMATELY BE ABLE TO CREATE
            // THE CHORDS FROM THE NOTES. THE CHORD TYPE COULD
            // BE DETERMINED BY CONVERTING THE NOTES TO INTERVALS
            // AND ASKING THE ChordType CLASS TO RETURN THE CHORD
            // TYPE THAT HAS THOSE INTERVALS
            // THE FIRST NOTE WOULD ALWAYS BE CONSIDERED THE ROOT???
            switch (position) {
                case TONIC:
                case SUBDOMINANT:
                case DOMINANT:
                    chords.add(new Chord(note, ChordType.getChordType("Major")));
                    break;
                case SUPERTONIC:
                case MEDIANT:
                case SUBMEDIANT:
                    chords.add(new Chord(note, ChordType.getChordType("Minor")));
                    break;
                case LEADINGTONE:
                    chords.add(new Chord(note, ChordType.getChordType("Diminished")));
                    break;
            }

            position++;
        }
    }

    public int getNamingIndex() {
        return scale.getNamingIndex();
    }

    public String getName() {
        return scale.getName();
    }

    public String toString() {
        String output = scale.getName() + ": ";
        for (Chord chord : chords) {
            output += chord.getName() + " ";
        }

        return output;
    }

    public static Collection<Key> getKeys() {
        return keys.values();
    }

    public static Key getKey(String _scale) {
        return keys.get(_scale);
    }

    public static Key getKey(Scale _scale) {
        return keys.get(_scale.getName());
    }
}
